#vertex shader

#version 130

struct Material {
	vec4 ambient;
	vec4 diffuse;
	vec4 specular;
	vec4 emissive;
	float shininess;
};

struct Light {
	vec4 ambient;
	vec4 diffuse;
	vec4 position;
	vec4 specular;
	float constantAttenuation;
	float linearAttenuation;
	float quadraticAttenuation;
	vec4 spotDirection;
	float spotExponent;
	float spotCutoff;
};

uniform int maxLights;
uniform Material material;
uniform Light lights[8];

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;

in vec3 vertex_in;
in vec3 normal_in;
in vec2 texcoord_in;

out vec4 color;
out vec2 texcoord;

void main() {
	vec3 vertex = vec3(viewMatrix * modelMatrix * vec4(vertex_in, 1.0));
	vec3 normal = normalize(normalMatrix * normal_in);
	vec3 eye = normalize(-vertex);
	
	float attenuation = 1.0;
	
	color = vec4(0.0, 0.0, 0.0, 0.0);
	
	for(int i = 0; i < maxLights; i++) {
		//ambient coloring
		vec4 ambient = lights[i].ambient * material.ambient;
		
		vec3 light;
	   	if(lights[i].position.w <= 0.5) {
	   		light = normalize(mat3(viewMatrix) * lights[i].position.xyz);
	   	} else {
			vec3 vertexToLightSource = vec3(viewMatrix * lights[i].position) - vertex;
		
			light = normalize(vertexToLightSource);
			
			float dist = length(vertexToLightSource);
			
			attenuation = 1.0 / (lights[i].constantAttenuation +
								lights[i].linearAttenuation * dist +
								lights[i].quadraticAttenuation * dist * dist);
								
            if(lights[i].spotCutoff <= 90.0) {  // spotlight?
				float clampedCosine = max(0.0, dot(-light, vec3(viewMatrix * lights[i].spotDirection)));
                
				if (clampedCosine < cos(lights[i].spotCutoff * 3.14159 / 180.0)) { // outside of spotlight cone?
                    attenuation = 0.0;
                } else {
                    attenuation = attenuation * pow(clampedCosine, max(lights[i].spotExponent, 0.1));
                }
            }
	   	}
		
		//diffuse coloring
		vec4 diffuse = lights[i].diffuse * material.diffuse;
		diffuse = diffuse * max(dot(normal, light), 0.0);
		
		//reflection
		vec3 reflect = normalize(-reflect(light, normal));
		
		 // calculate Specular Term:
   		vec4 specular = lights[i].specular * material.specular * pow(max(dot(reflect, eye), 0.0), 0.3 * max(material.shininess, 0.1));
   		specular = clamp(specular, 0.0, 1.0);
		
		color += attenuation * (ambient + diffuse + specular);
	}
	
	color += material.emissive;
	color.w = 1.0;
	
	texcoord = texcoord_in;
	gl_Position = projectionMatrix * vec4(vertex, 1.0);
}

#fragment shader

#version 130

uniform sampler2D tex;
uniform int useTexture;

in vec4 color;
in vec2 texcoord;

out vec4 fragColor;
 
void main() {
	vec4 pixelColor = texture(tex, texcoord);
	
	if(useTexture == 0) {
		pixelColor = vec4(1.0, 1.0, 1.0, 1.0);
	}
	
    fragColor = clamp(vec4(pixelColor.xyz, 1.0) * color, 0.0, 1.0);
}